﻿#region Using Statements
using System;
using System.Diagnostics;
using GameBase.Graphics;
using GameBase.Screens;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StarFox.Graphics;
#endregion

namespace StarFox.ScreenComponents
{
    /// <summary>
    /// Implementation of an animated background for menu screens.
    /// </summary>
    public class MenuBackground : ScreenComponent3D, IDisposable
    {
        #region Fields

        Effect effect;
        EffectParameter ep_Alpha;
        EffectParameter ep_Scale;
        QuadRenderer quad;

        PostScreenProcessor postScreenProcessor;

        double bkgTime;

        #endregion

        #region Properties

        /// <summary>
        /// Sets the duration of the animation.
        /// </summary>
        public TimeSpan Duration
        {
            private get;
            set;
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="screen">The Screen that this ScreenComponent3D is associated to.</param>
        public MenuBackground(Screen screen)
            : base(screen)
        {
            postScreenProcessor = Game.Services.GetService(typeof(PostScreenProcessor)) as PostScreenProcessor;
            if (postScreenProcessor == null)
                throw new InvalidOperationException("Service of type PostScreenProcessor not found");

            quad = new QuadRenderer(GraphicsDevice);

            Vector2 pixelSize = new Vector2(1.0f / (float)GraphicsDevice.PresentationParameters.BackBufferWidth,
                                            1.0f / (float)GraphicsDevice.PresentationParameters.BackBufferHeight);
            
            effect = Game.Content.Load<Effect>(ContentSettings.GetAsset("BACKGROUND_EFFECT")).Clone();
            effect.Parameters["BackgroundMap"].SetValue(Game.Content.Load<Texture2D>(ContentSettings.GetAsset("BACKGROUND_TEXTURE")));                
            effect.Parameters["HalfPixelOffset"].SetValue(pixelSize * 0.5f);
            effect.Parameters["Color"].SetValue(Color.Yellow.ToVector4());
            ep_Alpha = effect.Parameters["Alpha"];
            ep_Scale = effect.Parameters["Scale"];
        }

        #endregion

        #region Dispose

        // dispose flag
        bool isDisposed = false;

        /// <summary>
        /// Immediately releases all resources used by this object.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection.
        /// </summary>
        ~MenuBackground()
        {
            Dispose(false);
        }

        /// <summary>
        /// Releases the unmanaged resources used by this object and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!isDisposed)
            {
                if (disposing)
                {
                    if (effect != null) { effect.Dispose(); effect = null; }
                }

                isDisposed = true;
            }
        }

        #endregion

        #region Update

        /// <summary>
        /// Called when the ScreenComponent3D needs to be updated.
        /// </summary>
        /// <param name="gameTime">Time passed since the last call to this method.</param>
        public override void Update(GameTime gameTime)
        {
            postScreenProcessor.BlurFactor = 0.0f;
            postScreenProcessor.BloomThreshold = 0.0f;
            postScreenProcessor.BloomIntensity = 2.0f;
            postScreenProcessor.BaseIntensity = 1.0f;
            postScreenProcessor.BloomSaturation = 1.0f + (float)Math.Cos(MathHelper.TwoPi * gameTime.TotalGameTime.TotalSeconds / Duration.TotalSeconds);
            postScreenProcessor.BaseSaturation = 1.0f - (float)Math.Cos(MathHelper.TwoPi * gameTime.TotalGameTime.TotalSeconds / Duration.TotalSeconds);
            postScreenProcessor.Color = Color.Transparent;
        }

        #endregion

        #region Draw

        /// <summary>
        /// Called when the ScreenComponent3D needs to be updated.
        /// </summary>
        /// <param name="gameTime">Time passed since the last call to this method.</param>
        public override void Draw(GameTime gameTime)
        {
            GraphicsDevice.BlendState = BlendState.AlphaBlend;
            GraphicsDevice.DepthStencilState = DepthStencilState.None;
            GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;

            bkgTime += gameTime.ElapsedGameTime.TotalSeconds;

            // normalized time
            float time = (float)((bkgTime / Duration.TotalSeconds) % 1.0f);

            for (int i = 0; i < 2; i++)
            {
                if (time > 0.5f) { ep_Alpha.SetValue(2.0f - time * 2.0f); }
                else { ep_Alpha.SetValue(time * 2); }

                ep_Scale.SetValue(1.0f + 0.5f * time);

                effect.CurrentTechnique.Passes[0].Apply();
                quad.Draw();

                time = (time + 0.5f) % 1.0f;
            }
        }

        #endregion
    }
}
